import os
import sys
import subprocess
import time
import platform
import webbrowser
from threading import Thread
import os
import socket

# 检查Python版本
if sys.version_info < (3, 7):
    print("错误: 本应用需要Python 3.7或更高版本")
    sys.exit(1)

def is_port_open(host, port):
    """检查指定主机和端口是否开放"""
    try:
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.settimeout(2)
        result = sock.connect_ex((host, port))
        return result == 0
    except:
        return False
    finally:
        sock.close()

def check_dependencies():
    """检查项目依赖"""
    try:
        # 检查是否已安装requirements.txt中的依赖
        import flask
        import celery
        import redis
        import sqlalchemy
        import xgboost
        import pandas
        import numpy
        import streamlit
        print("✓ 项目依赖已安装")
        return True
    except ImportError:
        print("✗ 缺少必要的项目依赖")
        return False

def install_dependencies():
    """安装项目依赖"""
    try:
        print("正在安装项目依赖...")
        requirements_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "requirements.txt")
        subprocess.run([sys.executable, "-m", "pip", "install", "-r", requirements_path], check=True)
        print("✓ 项目依赖安装成功")
        return True
    except Exception as e:
        print(f"✗ 安装项目依赖失败: {str(e)}")
        print("请手动安装依赖: pip install -r requirements.txt")
        return False

def check_redis():
    """检查Redis是否可用"""
    try:
        import redis
        r = redis.Redis(host='localhost', port=6379)
        # 尝试执行一个简单的命令
        r.ping()
        print("✓ Redis服务已启动")
        return True
    except Exception as e:
        print(f"✗ Redis服务不可用: {str(e)}")
        return False

def start_redis_windows():
    """在Windows上启动Redis服务"""
    try:
        # 检查是否安装了Redis
        if os.path.exists("C:\Program Files\Redis\redis-server.exe"):
            print("正在启动Redis服务...")
            subprocess.Popen(["C:\Program Files\Redis\redis-server.exe"], shell=True)
            time.sleep(2)  # 给Redis一些时间启动
            return check_redis()
        else:
            print("未找到Redis安装。请先安装Redis并添加到系统路径。")
            print("Redis下载地址: https://github.com/microsoftarchive/redis/releases")
            return False
    except Exception as e:
        print(f"✗ 启动Redis服务失败: {str(e)}")
        return False

def start_flask_app():
    """启动Flask应用 - 直接运行app.py，不捕获输出以显示详细错误信息"""
    try:
        print("正在启动Flask应用(直接运行app.py)...")
        
        # 不捕获输出流，直接输出到控制台，这样可以看到完整的错误信息
        flask_process = subprocess.Popen([
            sys.executable, 
            "app.py"
        ], cwd=os.path.dirname(os.path.abspath(__file__)))
        
        # 添加环境变量调试信息
        print(f"  当前工作目录: {os.path.dirname(os.path.abspath(__file__))}")
        print(f"  FLASK_APP环境变量: {os.environ.get('FLASK_APP', '未设置')}")
        print(f"  FLASK_ENV环境变量: {os.environ.get('FLASK_ENV', '未设置')}")
        print("  注意: 所有输出将直接显示在控制台，不进行捕获")
        
        # 等待Flask启动
        time.sleep(3)
        
        # 检查Flask是否正常启动
        if flask_process.poll() is not None:
            # Flask进程已经退出，说明启动失败
            print(f"✗ Flask应用启动失败，请查看上方的详细错误信息")
            return None
        
        print("✓ Flask应用已启动在 http://localhost:5000 (调试模式)")
        return flask_process
    except Exception as e:
        print(f"✗ 启动Flask应用失败: {str(e)}")
        return None

def start_celery_worker():
    """启动Celery worker"""
    try:
        print("正在启动Celery worker...")
        
        # 为了避免循环导入，我们使用单独的celery配置模块
        # 或者在无法找到正确配置时直接跳过启动
        try:
            # 尝试启动Celery worker
            celery_process = subprocess.Popen([
                sys.executable, 
                "-m", 
                "celery", 
                "-A", 
                "app.services.celery_config", 
                "worker", 
                "--loglevel=info"
            ], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            
            # 等待Celery启动
            time.sleep(3)
            
            # 检查Celery是否正常启动
            if celery_process.poll() is not None:
                # Celery进程已经退出，说明启动失败
                error_output = celery_process.stderr.read().decode()
                print(f"✗ Celery worker启动失败: {error_output}")
                print("⚠ 系统将在没有Celery任务队列的模式下继续运行")
                return None
            
            print("✓ Celery worker已启动")
            return celery_process
        except Exception as e:
            print(f"✗ 启动Celery worker失败: {str(e)}")
            print("⚠ 系统将在没有Celery任务队列的模式下继续运行")
            return None
    except Exception as e:
        print(f"✗ 启动Celery worker失败: {str(e)}")
        return None

def start_streamlit_frontend():
    """启动Streamlit前端"""
    try:
        print("正在启动Streamlit前端...")
        
        # 构建前端应用路径
        frontend_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "app", "frontend", "app.py")
        
        # 启动Streamlit
        streamlit_process = subprocess.Popen([
            sys.executable, 
            "-m", 
            "streamlit", 
            "run", 
            frontend_path,
            "--server.port=8501"
        ], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        
        # 等待Streamlit启动
        time.sleep(5)
        
        # 检查Streamlit是否正常启动
        if streamlit_process.poll() is not None:
            # Streamlit进程已经退出，说明启动失败
            error_output = streamlit_process.stderr.read().decode()
            print(f"✗ Streamlit前端启动失败: {error_output}")
            return None
        
        print("✓ Streamlit前端已启动在 http://localhost:8501")
        
        # 自动打开浏览器
        try:
            webbrowser.open("http://localhost:8501")
            print("✓ 已尝试打开浏览器访问Streamlit前端")
        except:
            print("提示: 请手动打开浏览器访问 http://localhost:8501")
        
        return streamlit_process
    except Exception as e:
        print(f"✗ 启动Streamlit前端失败: {str(e)}")
        return None

def start_vue_frontend():
    """启动Vue 3前端"""
    try:
        print("正在启动Vue 3前端...")
        
        # 构建前端应用路径
        frontend_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "frontend")
        
        # 检查是否安装了npm
        try:
            subprocess.run(["npm", "--version"], check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            print("✓ npm已安装")
        except (subprocess.CalledProcessError, FileNotFoundError):
            print("✗ npm未安装，请先安装Node.js和npm")
            print("Node.js下载地址: https://nodejs.org/")
            return None
        
        # 检查是否已安装依赖
        node_modules_path = os.path.join(frontend_path, "node_modules")
        if not os.path.exists(node_modules_path):
            print("正在安装Vue前端依赖...")
            npm_install_process = subprocess.Popen(
                ["npm", "install"], 
                cwd=frontend_path,
                stdout=subprocess.PIPE, 
                stderr=subprocess.PIPE
            )
            
            # 等待npm install完成
            print("正在安装依赖，请耐心等待...")
            npm_install_process.wait()
            
            if npm_install_process.returncode != 0:
                error_output = npm_install_process.stderr.read().decode()
                print(f"✗ Vue前端依赖安装失败: {error_output}")
                return None
            print("✓ Vue前端依赖安装成功")
        else:
            print("✓ Vue前端依赖已存在")
        
        # 启动Vue开发服务器
        vue_process = subprocess.Popen(
            ["npm", "run", "dev"], 
            cwd=frontend_path,
            stdout=subprocess.PIPE, 
            stderr=subprocess.PIPE
        )
        
        # 等待Vue服务器启动
        time.sleep(5)
        
        # 检查Vue是否正常启动
        if vue_process.poll() is not None:
            # Vue进程已经退出，说明启动失败
            error_output = vue_process.stderr.read().decode()
            print(f"✗ Vue前端启动失败: {error_output}")
            return None
        
        print("✓ Vue 3前端已启动 (通常在 http://localhost:5173 或 http://localhost:3000)")
        
        # 自动打开浏览器
        try:
            # 尝试打开Vue默认端口
            webbrowser.open("http://localhost:5173")
            print("✓ 已尝试打开浏览器访问Vue前端")
        except:
            print("提示: 请手动打开浏览器访问Vue前端")
        
        return vue_process
    except Exception as e:
        print(f"✗ 启动Vue前端失败: {str(e)}")
        return None

def setup_database():
    """初始化数据库"""
    try:
        print("正在初始化数据库...")
        
        # 导入数据库模型和Flask应用实例
        from app.models.database import db
        from app import app
        
        # 创建应用上下文
        with app.app_context():
            # 创建所有表
            db.create_all()
            print("✓ 数据库表已创建")
        
        return True
    except Exception as e:
        print(f"✗ 初始化数据库失败: {str(e)}")
        return False

def run_services():
    """运行所有服务"""
    # 初始化变量
    flask_process = None
    celery_process = None
    streamlit_process = None
    vue_process = None
    scheduler_process = None
    
    try:
        # 检查并安装依赖
        if not check_dependencies():
            if not install_dependencies():
                print("无法继续，缺少必要的依赖项。")
                return
        
        # 检查Redis服务
        if not check_redis():
            # 根据操作系统类型尝试启动Redis
            if platform.system() == 'Windows':
                if not start_redis_windows():
                    print("无法继续，Redis服务不可用。")
                    print("请手动启动Redis服务，然后再次运行此脚本。")
                    return
            else:
                print("提示: 请手动启动Redis服务:")
                print("  - Ubuntu/Debian: sudo systemctl start redis-server")
                print("  - macOS (使用Homebrew): brew services start redis")
                print("启动后请再次运行此脚本。")
                return
        
        # 初始化数据库
        setup_database()
        
        # 启动调度器
        try:
            # 延迟导入以避免循环导入问题
            from app.services.scheduler import scheduler
            scheduler.start()
            scheduler_process = scheduler  # 保存调度器实例以便后续停止
            print("✓ 调度器已启动")
        except Exception as e:
            print(f"✗ 调度器启动失败: {str(e)}")
            scheduler_process = None
        
        # 启动Flask应用
        flask_process = start_flask_app()
        if not flask_process:
            print("无法继续，Flask应用启动失败。")
            return
        
        # 验证Flask服务是否可以访问
        if is_port_open('localhost', 5000):
            print("✓ Flask端口5000已开放，服务可访问")
        else:
            print("⚠ 警告: Flask端口5000可能无法正常访问，请检查防火墙设置")
        
        # 启动Celery worker
        celery_process = start_celery_worker()
        if not celery_process:
            print("警告: Celery worker启动失败，但仍可继续使用部分功能。")
        
        # 启动Vue前端
        vue_process = start_vue_frontend()
        if not vue_process:
            print("警告: Vue前端启动失败，但仍可继续使用其他功能。")
        
        # 启动Streamlit前端
        streamlit_process = start_streamlit_frontend()
        if not streamlit_process:
            print("警告: Streamlit前端启动失败，但仍可继续使用其他功能。")
        
        # 显示启动成功信息
        print("\n======================================")
        print("智能化漏洞检测与攻击路径分析平台已启动!")
        print("======================================")
        print("服务访问地址:")
        print("- Vue 3前端: http://localhost:5173 (或其他端口)")
        print("- Streamlit前端: http://localhost:8501")
        print("- Flask API: http://localhost:5000 (调试模式)")
        print("\n使用说明:")
        print("1. 在浏览器中打开Streamlit前端")
        print("2. 在'演示模式'中可以快速查看系统功能")
        print("3. 在'扫描任务提交'中可以提交新的扫描任务")
        print("\n调试信息:")
        print("- Flask运行在调试模式，详细日志已启用")
        print("- 如遇连接问题，请检查控制台输出的详细错误信息")
        print("\n按 Ctrl+C 停止所有服务...")
        print("======================================")
        
        # 保持脚本运行
        while True:
            time.sleep(1)
    
    except KeyboardInterrupt:
        print("\n正在停止所有服务...")
        
        # 停止调度器
        if scheduler_process:
            try:
                scheduler_process.stop()
                print("✓ 调度器已停止")
            except Exception as e:
                print(f"✗ 调度器停止时出错: {str(e)}")
        
        # 优雅地停止所有进程
        if vue_process:
            vue_process.terminate()
            vue_process.wait(timeout=5)
            print("✓ Vue前端已停止")
        
        if streamlit_process:
            streamlit_process.terminate()
            streamlit_process.wait(timeout=5)
            print("✓ Streamlit前端已停止")
        
        if celery_process:
            celery_process.terminate()
            celery_process.wait(timeout=5)
            print("✓ Celery worker已停止")
        
        if flask_process:
            flask_process.terminate()
            flask_process.wait(timeout=5)
            print("✓ Flask应用已停止")
        
        print("所有服务已停止。")
    
    except Exception as e:
        print(f"发生错误: {str(e)}")
        
        # 清理进程
        if vue_process:
            vue_process.terminate()
        
        if streamlit_process:
            streamlit_process.terminate()
        if celery_process:
            celery_process.terminate()
        if flask_process:
            flask_process.terminate()

if __name__ == "__main__":
    # 设置当前工作目录为脚本所在目录
    os.chdir(os.path.dirname(os.path.abspath(__file__)))
    
    # 运行所有服务
    run_services()